package com.kk.demo.java8.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

/**
 * ：随机生成一个数组，每个元素均是0-999之间的整数，
 * 统计该数组中每个数字出现1的次数的和。
 * 
 * 使用Fork／Join框架首先要考虑到的是如何分割任务
 * 1,数据按索引进行分隔，最的单位为1，即一个数组中的元素
 * 2,当得到单数据后，检查是否为1，如果为1，记数加1，否则为0
 * 3，将所有的结果汇总
 * 
 * @author kk
 * @version 0.0.1
 * @date 2017年3月7日
 */
public class CountTaskNum extends RecursiveTask<Integer> {

    /**
     * 统计的数组
     */
    private int[] num;

    /**
     * 开始索引
     */
    private int startIndex;

    /**
     * 结束索引
     */
    private int endIndex;

    public CountTaskNum(int[] num, int startIndex, int endIndex) {
        this.num = num;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    @Override
    protected Integer compute() {

        int count = 0;

        // 如果不是最小粒度则进一步分隔
        if (endIndex - startIndex > 1) {
            int mid = (startIndex + endIndex) / 2;
            CountTaskNum startNum = new CountTaskNum(num, startIndex, mid);
            CountTaskNum endNum = new CountTaskNum(num, mid, endIndex);

            // 执行计算
            startNum.fork();
            endNum.fork();

            // 获取结果
            int startResult = startNum.join();
            int endResult = endNum.join();

            // 返回结果
            count = startResult + endResult;
        }
        // 如果当前已经是最小粒度，则进行计算
        else {
            if (num[startIndex] == 1) {
                count = 1;
            }
        }

        return count;
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();

        int[] num = new int[] { 1, 2, 2, 1 };

        CountTaskNum count = new CountTaskNum(num, 0, num.length);

        // 执行计算
        Future<Integer> rsp = pool.submit(count);

        try {
            System.out.println(rsp.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
